package com.hzhc.netty;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName: WebSocketHandler类型， 表示一个文本帧
 * @Description:
 * @version 1.0
 * @author: duanhm
 * @Date: 2021/04/28 14:08:47
 *
 */
@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
	private static final Logger log = LogManager.getLogger(WebSocketHandler.class);

	/**
	 * 一旦连接，第一个被执行
	 *
	 * @param ctx
	 * @throws Exception
	 */
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		log.info("handlerAdded 被调用" + ctx.channel().id().asLongText());
		// 添加到channelGroup 通道组
		NettyConfig.getChannelGroup().add(ctx.channel());
	}

	/**
	 * 读取数据
	 */
	@SuppressWarnings("unused")
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
		log.info("服务器收到消息：{}", msg.text());

		// 获取用户ID,关联channel
		JSONObject jsonObject = JSONObject.parseObject(msg.text());
		String type = jsonObject.getString(NettyConfig.TYPE);
		String devid = jsonObject.getString(NettyConfig.DEVID);
		String userName = jsonObject.getString(NettyConfig.USERNAME);
		String userId = jsonObject.getString(NettyConfig.USERID);
		String deviceNo = jsonObject.getString(NettyConfig.DEVICENO);
		String machinemame = jsonObject.getString(NettyConfig.MACHINEMAME);
		if ("tc".equals(type)) {
			// 退出webscoket 单前设备用户
			NettyConfig.getUserChannelMap().remove(devid);
		} else {

			NettyConfig.getUserChannelMap().put(devid, ctx.channel());
			ConcurrentHashMap<String, Channel> userChannelMap = NettyConfig.getUserChannelMap();
			Channel channel = NettyConfig.getUserChannelMap().get(devid);
			// 将用户ID作为自定义属性加入到channel中，方便随时channel中获取用户ID
			AttributeKey<String> key = AttributeKey.valueOf(NettyConfig.DEVID);
			ctx.channel().attr(key).setIfAbsent(devid);

			AttributeKey<String> namekey = AttributeKey.valueOf(NettyConfig.USERNAME);
			ctx.channel().attr(namekey).setIfAbsent(userName);

			AttributeKey<String> userIdkey = AttributeKey.valueOf(NettyConfig.USERID);
			ctx.channel().attr(userIdkey).setIfAbsent(userId);

			AttributeKey<String> deviceNoKey = AttributeKey.valueOf(NettyConfig.DEVICENO);
			ctx.channel().attr(deviceNoKey).setIfAbsent(deviceNo);

			AttributeKey<String> machinemameKey = AttributeKey.valueOf(NettyConfig.MACHINEMAME);
			ctx.channel().attr(machinemameKey).setIfAbsent(machinemame);

		}

		// 回复消息
		ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"msg\":\"服务器连接成功！\",\"type\":\"df\"}"));
		// 发送全局消息
		if ("sx".equals(type) || "tc".equals(type)) {
			SendAllMessages("onlineType");
		}

	}

	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		log.info("handlerRemoved 被调用" + ctx.channel().id().asLongText());
		// 删除通道
		NettyConfig.getChannelGroup().remove(ctx.channel());
		removeUserId(ctx);
		// 发送全局消息
		SendAllMessages("onlineType");
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		log.info("异常：{}", cause.getMessage());
		// 删除通道
		NettyConfig.getChannelGroup().remove(ctx.channel());
		removeUserId(ctx);
		// 发送全局消息
		SendAllMessages("onlineType");
		ctx.close();
	}

	/**
	 * 删除用户与channel的对应关系
	 *
	 * @param ctx
	 */
	private void removeUserId(ChannelHandlerContext ctx) {
		AttributeKey<String> key = AttributeKey.valueOf(NettyConfig.DEVID);
		String userId = ctx.channel().attr(key).get();
		if (StrUtil.isNotBlank(userId)) {
			NettyConfig.getUserChannelMap().remove(userId);
		}
	}

	// 给每个人发送消息,除发消息人外
	private void SendAllMessages(String type) {
		JSONObject o = new JSONObject();
		o.put("type", type);
		o.put("msg", "有用户更新，请刷新页面");
		ConcurrentHashMap<String, Channel> channelGroup = NettyConfig.getUserChannelMap();
		channelGroup.forEach((k, v) -> {
			v.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(o)));
		});
	}

}
